﻿using System;
using System.Collections.Generic;
using CodeParser.Tokens;

namespace CodeParser.Expressions
{
    public static class ParseUtils
    {

        public static int? FindClosingBracket(Token[] tokens, int index, TokenType open, TokenType close)
        {
            if (tokens[index].Type != open) throw new Exception("Index should point to a opening bracket for which the closing bracket must be found.");
            var count = 1;
            var tokenCount = tokens.Length;
            for (var i = index + 1; i < tokenCount; i++)
            {
                var currentToken = tokens[i];
                if (currentToken.Type == open) count++;
                if (currentToken.Type == close) count--;
                if (count == 0) return i;
            }
            return null;
        }

        public static int? FindClosingBracket(Token[] tokens, int index, string open, string close)
        {
            if (tokens[index].Value != open) throw new Exception("Index should point to a opening bracket for which the closing bracket must be found.");
            var count = 1;
            var tokenCount = tokens.Length;
            for (var i = index + 1; i < tokenCount; i++)
            {
                var currentToken = tokens[i];
                if (currentToken.Value == open) count++;
                if (currentToken.Value == close) count--;
                if (count == 0) return i;
            }
            return null;
        }

        public static Token[] GetCodeBlockTokens(Token[] tokens, int index, TokenType open, TokenType close)
        {
            if (tokens[index].Type == TokenType.CurlyOpen)
            {
                var closeIndex = FindClosingBracket(tokens, index, open, close);
                return closeIndex.HasValue ? tokens.SubSet(index, closeIndex.Value - index + 1)
                                           : tokens.SubSet(index);
            }
            return null;
        }

        /// <summary>
        /// Splits tokenchain into separated tokens with a given separator token type.
        /// Also ignores subcodeblocks delimited by (, [ or {.
        /// </summary>
        /// <param name="tokens"></param>
        /// <param name="index"></param>
        /// <param name="length"></param>
        /// <param name="splitter"></param>
        /// <returns></returns>
        public static List<List<Token>> SplitTokenChain(Token[] tokens, int index, int length, TokenType splitter)
        {
            var round = 0;
            var square = 0;
            var curly = 0;
            var listList = new List<List<Token>>();
            var list = new List<Token>();
            for (var i = index; i < index + length; i++)
            {
                var token = tokens[i];
                if (token.Type == TokenType.RoundOpen) round++;
                if (token.Type == TokenType.SquareOpen) square++;
                if (token.Type == TokenType.CurlyOpen) curly++;
                if (token.Type == TokenType.RoundClose) round--;
                if (token.Type == TokenType.SquareClose) square--;
                if (token.Type == TokenType.CurlyClose) curly--;

                if (round <= 0 && square <= 0 && curly <= 0 && token.Type == splitter)
                {
                    listList.Add(new List<Token>() { token}); // add splitters too
                    listList.Add(list);
                    list = new List<Token>();
                }
                else
                {
                    list.Add(token);
                }
            }
            listList.Add(list); // add last part, only if at least one separator is detected
            return listList;
        }

        public static int? FindTokenIndex(Token[] tokens, int index, TokenType tokenType)
        {
            for (var i = index; i < tokens.Length; i++)
            {
                if (tokens[i].Type == tokenType)
                {
                    return i;
                }
            }
            return null;
        }

        public static int? FindTokenIndex(Token[] tokens, int index, string tokenValue)
        {
            for (var i = index; i < tokens.Length; i++)
            {
                if (tokens[i].Value == tokenValue)
                {
                    return i;
                }
            }
            return null;
        }

    }
}
